package com.sunxd.zstudy.juc.T20_ThreadPool.threadPool;

import lombok.SneakyThrows;

import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * execute 执行
 * addwork（）当小于核心线程或队列已满执行这个方法，直接创建新的线程，当大于核心线程<线程总数，并且阻塞队列已满时，则创建新的线程
 * addWorker(null, false)  在线程池里增加一个线程，主要是为了防止线程池的任务队列里有任务而没有线程可用的这种情况发生
 * Worker 实现run的接口，实现独占锁，不可冲入
 *      //注意这个 while 循环,在这里实现了 [线程复用] // 如果 task 为空，则通过getTask 来获取任务
 *      执行会一直执行任务
 * 现象当队列未满时，则一直使用核心线程执行。
 *
 * runwork里面为什么使用cas的排他锁，可以参考终止的时候，如果拿不到锁（使用排他锁，即使是自己，也拿不到），说明这个线程正在执行，不能停止，等待线程执行完毕。才能优雅的关闭线程
 *
 *
 *
 * 里面大量当使用了
 *
 *
 * 1.当前池中线程比核心数少，新建一个线程执行任务
 * 2.核心池已满，但任务队列未满，添加到队列中
 *      任务成功添加到队列以后，再次检查是否需要添加新的线程，因为已存在的线程可能被销毁
 *      如果线程池处于非运行状态，并且把当前的任务从任务队列中移除成功，则拒绝该任务
 *      如果之前的线程已被销毁完，新建一个线程
 * 3.核心池已满，队列已满，试着创建一个新线程
 *      如果创建新线程失败了，说明线程池被关闭或者线程池完全满了，拒绝任务
 *
 * newFixedThreadPool 用于负载比较大的服务器，为了资源的合理利用，需要限制当前线程数量
 * newCachedThreadPool 创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程; 并且没有核心线程，非核心线程数无上限，但是每个空闲的时间只有 60 秒，超过后就会被回收。
 * newSingleThreadExecutor 创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
 * ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后运行任务，或者定期执行任务。线程数根据cpu核数
 *

 *
 * @author: 作者名称
 * @date: 2021-09-14 16:29
 **/
public class T2_1_ThreadPoolExecutor {
    static ThreadPoolExecutor threadPoolExecutor = null;

    // ArrayBlockingQueue 各种队列自己选择
    // 拒绝策略，一般不用，自定义 ThreadPoolExecutor.CallerRunsPolicy,重写拒绝策略
    static {
//
//        ExecutorService executorService = Executors.newFixedThreadPool(5);
//        ExecutorService executorService = Executors.newScheduledThreadPool(5);
//        ExecutorService executorService = Executors.newCachedThreadPool();
//        ExecutorService executorService = Executors.newSingleThreadExecutor();
        threadPoolExecutor = new ThreadPoolExecutor(2, 4,
                60, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(4),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        for (int i = 0; i < 1; i++) {
            // 区别 execute 不带返回值，submit 带返回值
            threadPoolExecutor.execute(new TaskRunnable(i));
//            Future<String> submit = threadPoolExecutor.submit(new MyCallable(i));
//            System.out.println(submit.get());
            TimeUnit.SECONDS.sleep(1000);
            threadPoolExecutor.shutdown();
        }

        System.out.println("queue.size" + threadPoolExecutor.getQueue().size());
//        threadPoolExecutor.execute(new TaskRunnable(100));
//        threadPoolExecutor.submit(new MyCallable(100));
//        threadPoolExecutor.shutdown();
//        threadPoolExecutor.execute(() -> {
//            System.out.println(1);
//        });
//        threadPoolExecutor.submit(() -> {
//            System.out.println(2);
//        });


//        newWorkStealingPool
//        ExecutorService executorService = Executors.newWorkStealingPool();
//        List<Callable<Integer>> collect = IntStream.range(0, 20).boxed().map(integer -> (Callable<Integer>) () -> {
//            try {
//                TimeUnit.SECONDS.sleep(3);
//                System.out.println(String.format(" %s 线程正在执行", Thread.currentThread().getName()));
//
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            return integer;
//        }).collect(Collectors.toList());
//
//        List<Future<Integer>> futures = executorService.invokeAll(collect);
    }

    static class TaskRunnable implements Runnable {

        private int i;

        public TaskRunnable(int i) {
            this.i = i;
        }

        @SneakyThrows
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
            System.in.read();

        }
    }

    static class MyCallable<String> implements Callable<java.lang.String> {

        private int i;

        public MyCallable(int i) {
            this.i = i;
        }


        @Override
        public java.lang.String call() throws Exception {
            return "MyCallable" + i;
        }
    }

}
